/*
 * @author: zhjpaul
 * @author: hh2o4
 * @author: wangxing
 */ 

#ifndef SELF_DEFINED_STRUCT_H
#define SELF_DEFINED_STRUCT_H

namespace ns3 {

/**
 * The defination of control packet type.
 *
 * Used by OpenflowNetDevice, HostAgent, ControllerServer and HostMsgProcess
 */
enum InfoType
{
  SWITCH,         //!< From switch
  
  STREAM_SIZE,    //!< From host, stream size metadata info
  STREAM_TIME,    //!< From host, stream time metadata info
  PACKET,         //!< From host, packet metadata info
  DELAY,          //!< From host, delay info
  LOSS,           //!< From host, packet loss info
  CONGESTION,     //!< From host, congestion info

  DISTRIBUTE_TOS, //!< From controller, distribute tos info
  WFQ_ADJUST      //!< From controller, WFQ weight adjustment info
};

/**
 * The defination of control packet header.
 *
 * Control packet use tcp socket to send data. However, tcp socket would send and receive packets
 * as flow, it would receive multiple pacekts as only one packet. So, we need header to distinguish
 * multiple packets.
 */
struct packet_header
{
  uint8_t type;         //!< One of the InfoType
  uint16_t length;      //!< Length of packet
};
const size_t PACKET_HEADER = sizeof (packet_header);

/**
 * The defination of trace data packet header.
 *
 * Trace data packet could use tcp socket to send data. However, tcp socket would send and receive packets
 * as flow, it would receive multiple pacekts as only one packet, and remove socket tag before application layer.
 * So, we need header to distinguish multiple packets, and get the tos, delay info, and konw if a tream has ended.
 */
struct data_header
{
  uint16_t length;    //!< Length of packet
  uint8_t tos;        //!< Tos of stream
  bool is_end;        //!< Stream end flag. When current packet is the last one of stream, set it to true
};
const size_t DATA_HEADER = sizeof (data_header);

/**
 * The defination of stream information item.
 *
 * Including the information of distinguishing a stream
 */
struct StreamInfo
{
  uint32_t srcIp;       //!< Source ipv4 address
  uint32_t dstIp;       //!< Destination ipv4 address
  uint16_t srcPort;     //!< Source port
  uint16_t dstPort;     //!< Destination port
  uint8_t proto;        //!< Protocol number
  uint8_t tos;          //!< Tos value

  bool operator<(const StreamInfo &another) const {
    if (srcIp != another.srcIp) { 
      return srcIp < another.srcIp;
    }
    else if (dstIp != another.dstIp) {
      return dstIp < another.dstIp;
    }
    else if (srcPort != another.srcPort) {
      return srcPort < another.srcPort;
    }
    else if (dstPort !=  another.dstPort) {
      return dstPort < another.dstPort;
    }
    else if (proto != another.proto) {
      return proto < another.proto;
    }
    else {
      return tos < another.tos;
    }
  }
};
const size_t STREAM_INFO = sizeof (StreamInfo);

/**
 * The defination of srcIp-dstIp-tos struct.
 *
 * Including source/destination ipv4 address and tos value.
 */
struct IpTos
{
  uint32_t srcIp;     //!< Source ipv4 address
  uint32_t dstIp;     //!< Destination ipv4 address
  uint8_t tos;        //!< Tos value

  bool operator<(const IpTos &another) const {
    if (srcIp != another.srcIp) {
      return srcIp < another.srcIp;
    }
    else if (dstIp != another.dstIp) {
      return dstIp < another.dstIp;
    }
    else {
      return tos < another.tos;
    }
  }
};
const size_t IP_TOS_SIZE = sizeof (IpTos);

/**
 * The defination of ip-tos struct.
 *
 * Including ipv4 address and tos value.
 */
struct Entity
{
  uint32_t ip;      //!< Ipv4 address
  uint8_t tos;      //!< Tos value

  bool operator<(const Entity &another) const {
    if (ip != another.ip) {
      return ip < another.ip;
    }
    else {
      return tos < another.tos;
    }
  }
};
const size_t ENTITY = sizeof (Entity);

/**
 * The defination of stream size metadata. 
 *
 * When simulation start, HostAgent will send stream source ipv4 address, destination ipv4 address and total size to
 * contoller to ask the tos of each TraceClient application on the node. Only after kown the tos, we just send data.
 */
struct StreamSizeMetadata
{
  uint8_t appId;      //!< Application id on the node
  uint8_t tos;        //!< Tos of stream
  uint32_t srcIp;     //!< Stream source ipv4 address
  uint32_t dstIp;     //!< Stream destination ipv4 address
  uint32_t size;      //!< Total size(bytes) of stream
};
const size_t STREAM_SIZE_METADATA = sizeof (StreamSizeMetadata);

/**
 * The defination of stream level metadata.
 *
 * Record start time and complete time of each stream.
 */
struct StreamLevelMetadata
{
  int64_t startTime;       //!< Start time of stream
  int64_t completeTime;    //!< Complete time of stream
};
const size_t STREAM_LEVEL_METADATA = sizeof (StreamLevelMetadata);

/**
 * The defination of packet level metadata.
 *
 * Record packet level metadata of each stream.
 */
struct PacketLevelMetadata
{
  int64_t startTime;         //!< Time of receiving the fist packet
  uint64_t sending;          //!< Total bytes that have arrived NetDevice, but haven't been sent out
  int64_t sendingGap;        //!< The time interval from the first packet arriving
};
const size_t PACKET_LEVEL_METADATA = sizeof (PacketLevelMetadata);

/**
 * The defination of stream metadata.
 *
 * Record stream level metadata and packet level metadata of each stream.
 */
struct StreamMetadata
{
  StreamLevelMetadata streamMetadata;   //!< Stream level metadata
  PacketLevelMetadata packetMetadata;   //!< Pacekt level metadata
  bool streamCompleteFlag;              //!< The flag of stream complete. true: has completed, false: not completed 
  bool updateFlag;                      //!< The flag of updating packet level metadata. true: updated, false: not updated 
};
const size_t STREAM_METADATA = sizeof (StreamMetadata);

/**
 * The defination of packet loss information item.
 *
 * Record packet loss information.
 */
struct LossMsg
{
  uint32_t lost;          //!< The number of packet loss
  uint32_t received;      //!< The number of packet received
};
const size_t LOSS_MSG = sizeof (LossMsg);

/**
 * The defination of flow complete time information item.
 *
 * Record flow complete time information.
 */
struct FlowCompleteTime
{
  int64_t flowCompleteTimeSum;  //!< The total time of flow completed
  uint8_t completedFlowNum;     //!< The number of flow completed
};
const size_t FLOW_COMPLETE_TIME = sizeof (FlowCompleteTime);

/**
 * The defination of delay data information item.
 *
 * Record delay data information.
 */
struct DelayMsg
{
  int64_t totalDelay;           //!< The total delay
  uint32_t receivedPackets;     //!< The total number of packets received
};
const size_t DELAY_MSG = sizeof (DelayMsg);

/**
 * The defination of delay information item.
 *
 * Record delay information, including a flag(used in reported)
 */
struct DelayInfo
{
  DelayMsg delayMsg;    //!< Delay data 
  bool updateFlag;      //!< The flag of updating delay data. true: updated, false: not updated 
};
const size_t DELAY_INFO = sizeof (DelayInfo);

/**
 * The defination of bucket params item.
 *
 * Record bucket params information.
 */
struct BucketParams
{
  int64_t lastTime;         //!< Time of last packet arrival
  uint64_t tokens;          //!< Current total tokens
  uint64_t rate;            //!< Speed limit of TokenBucket
  uint64_t burst;           //!< Allowed burst size
  uint16_t counter;         //!< The counter of how many flows have the same <dstIp, tos> pair
  uint32_t ecnPackets;      //!< The number of packet with ecn
  uint32_t totalPackets;    //!< The total number of received packets
};
const size_t BUCKET_PARAMS = sizeof (BucketParams);

/**
 * The defination of congestion information item.
 *
 * Record congestion information.
 */
struct CongestionMsg
{
  uint8_t tos;                //!< Tos value
  uint32_t ecnPackets;        //!< The number of packet with ecn flag
  uint32_t totalPackets;      //!< The number of packet received
};
const size_t CONGESTION_MSG = sizeof (CongestionMsg);

/**
 * The defination of switch netdevice port information item.
 *
 * Record switch netdevice port information used for calculate link utilization rate.
 */
struct PortInfo
{
  uint16_t port_no;       //!< Port id of switch
  uint16_t rx_bytes[4];   //!< The total bytes received, and actuallt it is uint64_t.
  uint16_t tx_bytes[4];   //!< The total bytes sent, and actuallt it is uint64_t.
};
const size_t PORT_INFO = sizeof (PortInfo);

/**
 * The defination of srcNode-dstNode-tos struct.
 *
 * Used to set dafault routes.
 */
struct NodeTos
{
  uint16_t srcNode;     //!< Source node id
  uint16_t dstNode;     //!< Destination node id
  uint8_t tos;          //!< Tos value
};
const size_t NODE_TOS = sizeof (NodeTos);


const size_t DOUBLE_SIZE = sizeof (double);
const size_t UINT16_SIZE = sizeof (uint16_t);
const size_t UINT32_SIZE = sizeof (uint32_t);

} // namespace ns3

#endif  /* SELF_DEFINED_STRUCT_H */
